package com.jrapider.session;

import com.jrapider.om.JSONResult;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @Auther: hxs
 * @Date: 2019/1/4
 * @Description:
 */
@Log4j2
@Component
public class SessionFilter implements Filter {
    private List<String> excludesPattern = new ArrayList<>();
    @Autowired(required = false)
    private SessionWhitePage sessionWhitePage;
    private String contextPath;

    protected ServletPathMatcher pathMatcher = new ServletPathMatcher();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        if (sessionWhitePage == null) {
            sessionWhitePage = new SessionWhitePage.DefaultSessionWhitePage();
        }
        contextPath = filterConfig.getServletContext().getContextPath();
        sessionWhitePage.buildPage();
        excludesPattern = sessionWhitePage.pageList;
        excludesPattern.add("/js/*");
        excludesPattern.add("/css/*");
        excludesPattern.add("/layui/*");

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        //忽略掉OPTIONS请求的检查
        if (req.getMethod().equals("OPTIONS") || "FORWARD".equals(req.getDispatcherType().name())) {
            chain.doFilter(request, response);
        } else {
            String requestURI = getURI(req.getRequestURI());
            if (isMatch(requestURI, excludesPattern)) {
                chain.doFilter(request, response);
            } else {
                log.debug("访问:" + requestURI);
                if (UserSession.existUser()) {
                    chain.doFilter(request, response);
                } else {
                    timeout(req, (HttpServletResponse) response);
                }
            }

        }
    }

    private String getURI(String requestURI) {
        if (contextPath != null && requestURI.startsWith(contextPath)) {
            requestURI = requestURI.substring(contextPath.length());
            if (!requestURI.startsWith("/")) {
                requestURI = "/" + requestURI;
            }
        }
        return requestURI;
    }

    private boolean isMatch(String path, List<String> patterns) {
        if (patterns == null || path == null) {
            return false;
        }
        for (String pattern : patterns) {
            if (pathMatcher.matches(pattern, path)) {
                return true;
            }
        }
        return false;
    }

    @Value("${jrapider.login-page-user:/page/login}")
    private String loginPageUrl;

    public void timeout(HttpServletRequest request, HttpServletResponse response) {
        String accept = request.getHeader("accept");
        Enumeration<String> headers = request.getHeaderNames();
        log.info("会话过期RequestHeader");
        while (headers.hasMoreElements()) {
            String header = headers.nextElement();
            log.debug(header + ":" + request.getHeader(header));
        }
        //判断是HTML请求，如果有统一认证，直接重定向
        if (accept != null && accept.indexOf("application/json") < 0) {
            try {
                response.sendRedirect(loginPageUrl);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } else {
            PrintWriter out = null;
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                response.setStatus(HttpStatus.UNAUTHORIZED.value());

                out = response.getWriter();
                out.println(JSONResult.newBuilder().fail("会话过期").build().toJSONString());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                if (out != null) {
                    out.close();
                }

            }
        }

    }

    @Override
    public void destroy() {

    }
}
